package com.maben.security.config;

import com.maben.security.filter.JwtAuthenticationFilter;
import com.maben.security.filter.RedisTokenFilter;
import com.maben.security.util.JwtUtils;
import com.maben.security.util.RedisTokenUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity // 开启 Spring Security 功能
public class SecurityConfig {
    // 密码加密器（Spring Security 5+ 必须配置，否则报错）
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 推荐使用 BCrypt 加密
    }

    //配置资源访问规则：哪些接口需要认证，哪些可以匿名访问
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // JWT 认证无需 CSRF
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态（不依赖 Session）
                .and()
                // 禁用默认表单登录（避免跳转登录页）
                .formLogin().disable()
                // 禁用默认退出功能（避免跳转页面）
                .logout().disable()
                // 配置请求授权规则
                .authorizeRequests(auth -> auth
                        .antMatchers("/export_file/**").permitAll() //配置外部可访问文件路径
                        .antMatchers("/json/**").permitAll() //配置内部访问文件路径
                        .antMatchers("/user/doLogin").permitAll() // jwt公开登录接口
                        .antMatchers("/user/login").permitAll() // redis公开登录接口
                        .antMatchers("/public/**").permitAll() // 公开接口，无需认证
                        //Spring Security 的 hasRole() 方法会自动给角色名添加 ROLE_ 前缀
                        //hasRole("ADMIN") 等价于 hasAuthority("ROLE_ADMIN")
                        .antMatchers("/admin/**").hasRole("ADMIN") // 仅 ADMIN 可访问
                        .anyRequest().authenticated() // 其他接口需认证
                )
                // 5. 配置错误处理器
                .exceptionHandling(ex -> ex
                        // 未认证（未登录）时，使用自定义处理器
                        .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                        // 权限不足时，使用自定义处理器
                        .accessDeniedHandler(new CustomAccessDeniedHandler())
                )
                // 添加token校验过滤器
//                .addFilterBefore(
//                        jwtAuthenticationFilter(),
//                        UsernamePasswordAuthenticationFilter.class
//                ) // 添加 JWT 过滤器（在用户名密码过滤器之前执行）
                .addFilterBefore(
                        redisTokenFilter(),
                        UsernamePasswordAuthenticationFilter.class
                ) // 添加 JWT 过滤器（在用户名密码过滤器之前执行）
        ;
        return http.build();
    }

    /**
     * 注入 AuthenticationManager（用于登录时验证用户名密码）
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    // 注入依赖（JwtUtils、UserDetailsService）
    @Resource
    private JwtUtils jwtUtils;
    @Resource
    private UserDetailsService userServiceImpl;

    /**
     * 手动创建过滤器（
     *     不再依赖 @Component，
     *     标注这个会自动注册spring的过滤器，这样公开接口就失效了，都被过滤器拦截了
     * ）
     */
    private JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter(jwtUtils, userServiceImpl);
    }

    @Resource
    private RedisTokenUtils redisTokenUtils;
    /**
     * 手动创建过滤器（
     *     不再依赖 @Component，
     *     标注这个会自动注册spring的过滤器，这样公开接口就失效了，都被过滤器拦截了
     * ）
     */
    private RedisTokenFilter redisTokenFilter() {
        return new RedisTokenFilter(redisTokenUtils, userServiceImpl);
    }

}
